package pCloud.service;

import pCloud.PCloudAttributeAndType;
import pCloud.Utilities;
import pCloud.server.DataStreamHandle;
import pCloud.stream.*;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.Vector;

import java.io.*;
import java.net.URI;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

import com.streambase.sb.StreamBaseException;
import com.streambase.sb.client.StreamBaseAdminClient;
import com.sun.xacml.Obligation;
import com.sun.xacml.attr.AttributeValue;
import com.sun.xacml.attr.StringAttribute;
import com.sun.xacml.ctx.RequestCtx;


// class StreamSchemaContenHandler is used by XML SAX parser

class StreamSchemaContentHandler implements ContentHandler{
		
	public Stream stream;
	
	public StreamSchemaContentHandler(QueryGraph qg){
		this.stream = qg.InputStream;		
	}

	public void startElement(String namespaceURI, String localName, String rawName, Attributes atts) {
		
		if (localName.equalsIgnoreCase(PCloudAttributeAndType.STREAM_TAG)){
						
			if (atts.getLength() == 1){
//				System.out.println("Stream Name is " + atts.getValue(0));				
				this.stream.name = atts.getValue(0);
			}
			else {
				System.err.println("XML file invalid, incorrect number of attributes for element " + localName);				
			}					
		}
		
		if (localName.equalsIgnoreCase(PCloudAttributeAndType.STREAM_ATTRIBUTE_TAG)){
			
			
			if (atts.getLength() == 2) {
				this.stream.attributes.add(new StreamAttribute(atts.getValue(0),atts.getValue(1)));	
			}
			else {
				System.err.println("XML file invalid, incorrect number of attributes for element " + localName);
				
			}
		}		
	}
	
	public void endElement(String namespaceURI, String localName, String rawName) {
		
		if (localName.equalsIgnoreCase("Stream")){
		}
	}
	
	public void startDocument(){
		
		System.out.println("start parsing schema file...");
	}
	
	public void endDocument(){
		
		System.out.println("...Parsing ends...");
	}
	
	public void	endPrefixMapping(String prefix){}

	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void ignorableWhitespace(char[] ch, int start, int length)
			throws SAXException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void processingInstruction(String target, String data)
			throws SAXException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setDocumentLocator(Locator locator) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void skippedEntity(String name) throws SAXException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void startPrefixMapping(String prefix, String uri)
			throws SAXException {
		// TODO Auto-generated method stub
		
	}
	
}

public class AuroraDataStreamHandle implements DataStreamHandle{

	String stream_engine_address;
	String stream_schema_dir;
	int stream_engine_port;
	
	
	public static int container_index = 0;
	
	
	public void init(String dir,String address, int port ){
		
		System.out.println("Initializing Stream Handler...");
		System.out.println("Stream Engine at " + address + ":" + port);
		System.out.println("Stream Schema Directory is " + dir);
		this.stream_engine_address = address;
		this.stream_engine_port = port;
		this.stream_schema_dir = dir;
		
	}
	
	
	//load the stream schema file 
	public void loadStreamSchema(String streamName,QueryGraph qg){
		
		String schemaFilePath = this.stream_schema_dir + "/" + streamName + ".xml";
		System.out.println("Schema File for " + streamName + " is \"" + schemaFilePath + "\"");
		
		StreamSchemaContentHandler schemahandler = new StreamSchemaContentHandler(qg);
		try {
			XMLReader parser = XMLReaderFactory.createXMLReader();
			parser.setContentHandler(schemahandler);
			parser.parse(schemaFilePath);				
			
		}
		catch (Exception e){			
			System.out.println(e.getMessage());
		}
		
	}
	
	
	public void generateQueryGraphFromObligation(Vector<FilterBox> filters, Vector<MapBox> maps, Vector<AggregateBox> aggregates, QueryGraph streamquery){
		
		streamquery.AB = aggregates;
		streamquery.FB = filters;
		streamquery.MB = maps;
				
	}	
	
	public String mergeQueryGraph(){
		
		String mergeResult="";
		
		return mergeResult;
	}
	
	
	//generate a query graph from user query
	
	public void generateQueryGraphFromQuery(){
		
		
	}
	
	
	// Retrieve the request stream name from Request.  

	
	public String getStreamName(RequestCtx requestCtx) throws Exception {
		
//		ArrayList<AttributeValue> requestedStreams = Utilities
//				.getAttributeValue(PCloudAttributeAndType.RESOURCE_STREAM_ID,
//						requestCtx.getResource());
		
		// temporarily use rdbms-table-id to replace stream-id
		
		System.out.println("Retrieving Stream Name...");
		
		ArrayList<AttributeValue> requestedStreams = Utilities
				.getAttributeValue(PCloudAttributeAndType.RESOURCE_TABLE_ID,
						requestCtx.getResource());
		
		if (requestedStreams.size() != 1) {
			System.err.println("Requested stream must be 1");
			return null;
		}
		System.out.println(requestedStreams.toString());
		return ((StringAttribute) requestedStreams.get(0)).getValue();
	}
	
	
	// sent the query graph to the stream engine, return success or error message if failed.
	
	public String addQueryGraph(String ssql, String outputStream){
		
		String uri = "sb://" + this.stream_engine_address + ":" + this.stream_engine_port;
		AuroraDataStreamHandle.container_index++;
		String msg = "";
				
		try {
			StreamBaseAdminClient sba = new StreamBaseAdminClient(uri);
			String container = "PCLOUD_CONTAINER_" + AuroraDataStreamHandle.container_index;
			
			System.out.println("Adding SSQL In Container : " + container + "...");
			
			sba.addContainer(container, ssql.getBytes(), new Vector<String>());

			
			// msg is URI for streambase client to connect to get output stream
			
			msg = uri+"/"+container+"/"+outputStream;
		}
		catch (StreamBaseException sbe) {
			
			System.out.println(sbe.getMessage());
			return sbe.getMessage();
		}
				
		return msg;
	}
	
	
	
	
	
}


